package com.logic.modular.game.player.science;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.comment.exception.ServiceException;
import com.logic.comment.lock.lock2.DistributedLock;
import com.logic.comment.util.XsRedisUtils;
import com.logic.config.netty.web.service.MessageService;
import com.logic.modular.game.player.bag.service.BagItemServiceImpl;
import com.logic.modular.game.player.bag.service.PlayerPropType1ServiceImpl;
import com.comment.pojo.domain.logic.domain.PlayerScience;
import com.logic.modular.game.player.science.mapper.PlayerScienceMapper;
import com.comment.pojo.domain.logic.core.CoreScienceConfig;
import com.comment.pojo.domain.logic.core.CoreSciencePropConfig;
import com.logic.modular.gameCore.cultivate.science.service.CoreScienceConfigServiceImpl;
import com.logic.modular.gameCore.cultivate.science.service.CoreSciencePropConfigServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.logic.modular.game.GameConstant.PLAYER_Science_KEY;

/**
 * 玩家科技表(PlayerScience)表服务实现类
 *
 * @author cxy
 * @since 2024-11-20 14:58:08
 */
@Slf4j
@Service
public class PlayerScienceService extends ServiceImpl<PlayerScienceMapper, PlayerScience> implements IPlayerScienceService {
    @Resource
    private XsRedisUtils xsRedisUtils;
    @Resource
    private BagItemServiceImpl bagItemServiceImpl;
    @Resource
    private PlayerPropType1ServiceImpl playerPropType1ServiceImpl;

    @Override
    public boolean updateById(PlayerScience entity) {
        boolean b = super.updateById(entity);
        if (b) {
            savaCache(entity);
            MessageService.sendMessageToUser(entity.getUid(), MessageService.updateJsonObject("playerScience", entity));
        }
        return b;
    }

    private void savaCache(PlayerScience entity) {
        String key = String.format(PLAYER_Science_KEY, entity.getUid());
        xsRedisUtils.set(key, entity, 60L, TimeUnit.MINUTES);
    }


    private PlayerScience selectCacheById(Long uid) {
        String key = String.format(PLAYER_Science_KEY, uid);
        return xsRedisUtils.getToBean(key, PlayerScience.class);
    }

    private PlayerScience getById(Long id) {
        PlayerScience playerScience = selectCacheById(id);
        if (playerScience == null) {
            playerScience = super.getById(id);
        }
        return playerScience;
    }

    public PlayerScience obtainPlayerScience(Long uid) {
        // 获取商店
        PlayerScience byId = getById(uid);
        if (byId == null) {
            byId = new PlayerScience();
            byId.setUid(uid);
            byId.setUseTime(0L);
            byId.setLastFlushTime(System.currentTimeMillis());
            boolean insert = byId.insert();
            if (insert) {
                byId = getById(uid);
                savaCache(byId);
            }
        }
        if (byId.getLastFlushTime()==null) {
            byId.setLastFlushTime(System.currentTimeMillis());
            updateById(byId);
        }
        return byId;
    }


    /**
     * 获取自然科技时间
     *
     * @param playerId 玩家id
     * @return 是否成功
     */
    @DistributedLock(key = "#playerId", lockTime = 10L, keyPrefix = "refreshCD-")
    public boolean refreshCD(Long playerId) {
        PlayerScience playerScience = obtainPlayerScience(playerId);
        Long lastPayTime = playerScience.getLastFlushTime();
        if (lastPayTime != null) {
            long lastPayTimeSecond = lastPayTime / 1000;
            long cSecond = System.currentTimeMillis() / 1000;
            long value = cSecond - lastPayTimeSecond; // 获取cd
            if (value > 0) {
                log.info("玩家:{},刷新cd({})成功", playerId, value);
                playerScience.useTime -= value; // 减cd
                if (playerScience.useTime < 0) {
                    playerScience.useTime = 0L;
                }
                playerScience.setLastFlushTime(System.currentTimeMillis());
                return updateById(playerScience);
            } else {
                log.info("玩家:{},距离上次刷新不足1s", playerId);
                return false;
            }
        }
        return false;
    }

    @DistributedLock(key = "#playerId", lockTime = 10L, keyPrefix = "consumeUseTime-")
    public void consumeUseTime(Long playerId, Long cost) {
        refreshCD(playerId);
        PlayerScience playerScience = obtainPlayerScience(playerId);
        // 获取上限
        CoreScienceConfig config = CoreScienceConfigServiceImpl.getCache(1L);
        Long maxCd = config.getValue1();

        Long useTime = playerScience.getUseTime(); // 当前cd
        boolean b = useTime > maxCd;
        if (b) {
            throw new ServiceException("cd不足");
        }
        playerScience.useTime += cost;
        updateById(playerScience);
    }


    /**
     * 购买科技道具
     *
     * @param uid           玩家uid
     * @param sciencePropId 道具id
     * @return 返回相关道具信息
     */
    public boolean pay(Long uid, Long sciencePropId) {
        CoreSciencePropConfig cache = CoreSciencePropConfigServiceImpl.getCache(sciencePropId);
        Long cd = cache.getCd();
        Long reward = cache.getReward();
        consumeUseTime(uid, cd);

        bagItemServiceImpl.obtainBagItem(uid, reward, new BigDecimal(1));
        return true;
    }


    /**
     * 科技加速
     *
     * @param uid 玩家uid
     * @return 返回相
     */
    public boolean accelerate(Long uid, Long accelerationTime) {
        CoreScienceConfig cache = CoreScienceConfigServiceImpl.getCache(1L);
        Map<Long, Integer> value2 = cache.getValue2();

        Map<Long, BigDecimal> undoData = new HashMap<>();
        for (Map.Entry<Long, Integer> entry : value2.entrySet()) {
            Long propId = entry.getKey();// 金额id
            BigDecimal amountOfMoney = new BigDecimal(entry.getValue());// 金额

            BigDecimal needMoney = new BigDecimal(accelerationTime).multiply(amountOfMoney);

            boolean b = playerPropType1ServiceImpl.tryPay(uid, propId, needMoney);
            if (b) {
                undoData.put(propId, needMoney);
            } else {
                undoData.forEach((k, v) -> bagItemServiceImpl.obtainBagItem(uid, k, v));
                throw new RuntimeException("时间货币不足");
            }
        }
        // 获取付费的时间
        PlayerScience playerScience = obtainPlayerScience(uid);
        playerScience.useTime -= 60 * accelerationTime;
        boolean b = updateById(playerScience);

        //
        if (b) {
            b = refreshCD(uid);
        }
        return b;
    }
}
